package com.swak.generate.codegen.dialects;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import com.swak.generate.codegen.RowSetMapper;
import com.swak.utils.Lists;

public abstract class AbstractOperater implements DatabaseOperater {

	private final String url;
	private final String userName;
	private final String passWord;
	protected Connection conn;
	protected AtomicBoolean opened = new AtomicBoolean(false);

	public AbstractOperater(String url, String userName, String passWord) {
		this.url = url;
		this.userName = userName;
		this.passWord = passWord;
		this.open();
	}

	private void open() {
		if (this.opened.get()) {
			this.close();
		}
		this.tryOpen();
	}

	private void tryOpen() {
		try {
			conn = DriverManager.getConnection(url, userName, passWord);
			this.opened.set(true);
		} catch (Exception e) {
			conn = null;
		}
	}

	@Override
	public void close() {
		try {
			this.opened.set(false);
			conn.close();
		} catch (Exception e) {
		}
	}

	/**
	 * 执行Sql
	 * 
	 * @param sql
	 * @throws SQLException
	 */
	@Override
	public void execSql(String sql) {
		PreparedStatement stmt = null;
		try {
			Boolean autoCommit = conn.getAutoCommit();
			conn.setAutoCommit(Boolean.FALSE);
			stmt = conn.prepareStatement(sql);
			stmt.execute();
			conn.setAutoCommit(autoCommit);
		} catch (Throwable e) {
			try {
				conn.rollback();
			} catch (Throwable e1) {
			}
		} finally {
			try {
				stmt.close();
			} catch (Throwable e) {
			}
		}
	}

	/**
	 * 执行Sql
	 * 
	 * @param sql
	 * @throws SQLException
	 */
	@Override
	public <T> List<T> execSql(String sql, RowSetMapper<T> mapper) {
		List<T> ts = Lists.newArrayList();
		PreparedStatement stmt = null;
		ResultSet result = null;
		try {
			Boolean autoCommit = conn.getAutoCommit();
			conn.setAutoCommit(Boolean.FALSE);
			stmt = conn.prepareStatement(sql);
			result = stmt.executeQuery();
			int row = 0;
			while (result.next()) {
				T t = mapper.mapRow(result, row++);
				ts.add(t);
			}
			conn.setAutoCommit(autoCommit);
		} catch (Throwable e) {
			try {
				conn.rollback();
			} catch (Throwable e1) {
			}
		} finally {
			try {
				result.close();
				stmt.close();
			} catch (Throwable e) {
			}
		}
		return ts;
	}
}